﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data.Common;

namespace BOHVote.Core
{
    public class Utility
    {
        #region <<  ConvertDatareaderToDataSet  >>
        /// <summary>
        /// Converts a IDataReader to a DataSet.  For use when a custom stored procedure returns an <see cref="IDataReader" />, it will 
        /// convert all result sets returned as a DataSet.
        /// </summary>
        /// <param name="reader">The reader to convert</param>
        /// <returns>A dataset with one table per result in the reader</returns>
        public static DataSet ConvertDataReaderToDataSet(IDataReader reader)
        {
            DataSet dataSet = new DataSet();
            do
            {
                // Create new data table

                DataTable schemaTable = reader.GetSchemaTable();
                DataTable dataTable = new DataTable();

                if (schemaTable != null)
                {
                    // A query returning records was executed

                    for (int i = 0; i < schemaTable.Rows.Count; i++)
                    {
                        DataRow dataRow = schemaTable.Rows[i];
                        // Create a column name that is unique in the data table
                        string columnName = (string)dataRow[Constant.UTILITY_COLUMNNAME];
                        // Add the column definition to the data table
                        DataColumn column = new DataColumn(columnName, (Type)dataRow[Constant.UTILITY_DATATYPE]);
                        dataTable.Columns.Add(column);
                    }

                    dataSet.Tables.Add(dataTable);

                    // Fill the data table we just created

                    while (reader.Read())
                    {
                        DataRow dataRow = dataTable.NewRow();

                        for (int i = 0; i < reader.FieldCount; i++)
                            dataRow[i] = reader.GetValue(i);

                        dataTable.Rows.Add(dataRow);
                    }
                }
                else
                {
                    // No records were returned

                    DataColumn column = new DataColumn(Constant.UTILITY_ROWSAFFECTED);
                    dataTable.Columns.Add(column);
                    dataSet.Tables.Add(dataTable);
                    DataRow dataRow = dataTable.NewRow();
                    dataRow[0] = reader.RecordsAffected;
                    dataTable.Rows.Add(dataRow);
                }
            }
            while (reader.NextResult());
            return dataSet;
        }
        #endregion


        #region "Execute Reader"
        /// <summary>
        /// Executes the <paramref name="dbCommand"/> and returns an <see cref="IDataReader"/> through which the result can be read. 
        /// It is the responsibility of the caller to close the connection and reader when finished. 
        /// </summary>
        /// <param name="transactionManager">The transaction to execute the command within.</param>
        /// <param name="dbCommand">The command that contains the query to execute.</param>
        /// <returns>An <see cref="IDataReader"/> object.</returns>
        /// <exception cref="System.Exception">The command could not be executed.</exception>
        /// <exception cref="System.Data.DataException">The <paramref name="transactionManager"/> is not open.</exception>
        /// <exception cref="System.Data.Common.DbException">The command could not be executed.</exception>
        public static IDataReader ExecuteReader(ITransactionManager transactionManager, DbCommand dbCommand)
        {
            if (!transactionManager.IsOpen)
                throw new DataException(Constant.UTILITY_TRANSACTION_UNOPEN_EXCEPTION);
            IDataReader results = null;
            try
            {
                results = transactionManager.Database.ExecuteReader(dbCommand, transactionManager.TransactionObject);
            }
            catch (Exception /*ex*/)
            {
                //PSB 2006-05-26: should we use EntLib ExceptionPolicy.HandleException?
                //if (ExceptionPolicy.HandleException(ex, exceptionPolicy)) throw;
                throw;
            }
            return results;
        }

        /// <summary>
        /// Executes the <paramref name="dbCommand"/> and returns an <see cref="IDataReader"/> through which the result can be read. 
        /// It is the responsibility of the caller to close the connection and reader when finished. 
        /// </summary>
        /// <param name="database">The database to execute the command within.</param>
        /// <param name="dbCommand">The command that contains the query to execute.</param>
        /// <returns>An <see cref="IDataReader"/> object.</returns>
        /// <exception cref="System.Exception">The command could not be executed.</exception>
        /// <exception cref="System.Data.Common.DbException">The command could not be executed.</exception>
        public static IDataReader ExecuteReader(Database database, DbCommand dbCommand)
        {
            IDataReader results = null;
            try
            {
                results = database.ExecuteReader(dbCommand);
            }
            catch (Exception ex)
            {
                //PSB 2006-05-26: should we use EntLib ExceptionPolicy.HandleException?
                //if (ExceptionPolicy.HandleException(ex, exceptionPolicy)) throw;
                throw ex;
            }
            return results;
        }
        #endregion

        #region "Execute Non Query"
        /// <summary>
        /// Executes the <paramref name="dbCommand"/> and returns the number of rows affected. 
        /// </summary>
        /// <param name="transactionManager">The transaction to execute the command within.</param>
        /// <param name="dbCommand">The command that contains the query to execute.</param>
        /// <returns>The number of rows affected.</returns>
        /// <exception cref="System.Exception">The command could not be executed.</exception>
        /// <exception cref="System.Data.DataException">The <paramref name="transactionManager"/> is not open.</exception>
        /// <exception cref="System.Data.Common.DbException">The command could not be executed.</exception>
        public static int ExecuteNonQuery(ITransactionManager transactionManager, DbCommand dbCommand)
        {
            if (!transactionManager.IsOpen)
                throw new DataException();
            int results = 0;
            try
            {
                results = transactionManager.Database.ExecuteNonQuery(dbCommand, transactionManager.TransactionObject);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return results;
        }

        /// <summary>
        /// Executes the <paramref name="dbCommand"/> and returns the number of rows affected. 
        /// </summary>
        /// <param name="database">The database to execute the command within.</param>
        /// <param name="dbCommand">The command that contains the query to execute.</param>
        /// <returns>The number of rows affected.</returns>
        /// <exception cref="System.Exception">The command could not be executed.</exception>
        /// <exception cref="System.Data.Common.DbException">The command could not be executed.</exception>
        public static int ExecuteNonQuery(Database database, DbCommand dbCommand)
        {
            int results = 0;
            try
            {
                results = database.ExecuteNonQuery(dbCommand);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return results;
        }
        #endregion

        #region Execute Scalar
        /// <summary>
        /// Executes the <paramref name="dbCommand"/> and returns  value of the first column of first column.
        /// </summary>
        /// <param name="database">The database to execute the command within.</param>
        /// <param name="dbCommand">The command that contains the query to execute.</param>
        /// <returns>the value of the first row and the first column.</returns>
        public static object ExecuteScalar(Database database, DbCommand dbCommand)
        {
            object results = null;
            try
            {
                results = database.ExecuteScalar(dbCommand);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return results;
        }

        /// <summary>
        /// Executes the <paramref name="dbCommand"/> and returns value of the first column of first column.
        /// </summary>
        /// <param name="transaction">The database to execute the command within.</param>
        /// <param name="dbCommand">The command that contains the query to execute.</param>
        /// <returns>value of the first column of the first row.</returns>
        public static string ExecuteScalar(ITransactionManager transaction, DbCommand dbCommand)
        {
            string results = "";
            try
            {
                results = transaction.Database.ExecuteScalar(dbCommand).ToString();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return results;
        }
        #endregion

        #region "Execute DataSet"
        /// <summary>
        /// Executes the <paramref name="dbCommand"/> and returns the results in a new <see cref="DataSet"/>. 
        /// </summary>
        /// <param name="transactionManager">The transaction to execute the command within.</param>
        /// <param name="dbCommand">The command that contains the query to execute.</param>
        /// <returns>A <see cref="DataSet"/> containing the results of the command.</returns>
        /// <exception cref="System.Exception">The command could not be executed.</exception>
        /// <exception cref="System.Data.DataException">The <paramref name="transactionManager"/> is not open.</exception>
        /// <exception cref="System.Data.Common.DbException">The command could not be executed.</exception>
        public static DataSet ExecuteDataSet(ITransactionManager transactionManager, DbCommand dbCommand)
        {
            if (!transactionManager.IsOpen)
                throw new DataException(Constant.UTILITY_TRANSACTION_UNOPEN_EXCEPTION);
            DataSet results = null;
            try
            {
                results = transactionManager.Database.ExecuteDataSet(dbCommand, transactionManager.TransactionObject);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return results;
        }

        /// <summary>
        /// Executes the <paramref name="dbCommand"/> and returns the results in a new <see cref="DataSet"/>. 
        /// </summary>
        /// <param name="database">The database to execute the command within.</param>
        /// <param name="dbCommand">The command that contains the query to execute.</param>
        /// <returns>A <see cref="DataSet"/> containing the results of the command.</returns>
        /// <exception cref="System.Exception">The command could not be executed.</exception>
        /// <exception cref="System.Data.Common.DbException">The command could not be executed.</exception>
        public static DataSet ExecuteDataSet(Database database, DbCommand dbCommand)
        {
            DataSet results = null;
            try
            {
                results = database.ExecuteDataSet(dbCommand);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return results;
        }

        #endregion

        #region <<  common  >>

        /// <summary>
        /// Get a default value for a given data type
        /// </summary>
        /// <param name="dataType">Data type for which to get the default value</param>
        /// <returns>An object of the default value.</returns>
        public static Object GetDefaultValue(DbType dataType)
        {
            switch (dataType)
            {
                case DbType.AnsiString:
                    return string.Empty;
                case DbType.AnsiStringFixedLength:
                    return string.Empty;
                case DbType.Binary:
                    return new byte[] { };
                case DbType.Boolean:
                    return false;
                case DbType.Byte:
                    return (byte)0;
                case DbType.Currency:
                    return 0m;
                case DbType.Date:
                    return DateTime.MinValue;
                case DbType.DateTime:
                    return DateTime.MinValue;
                case DbType.Decimal:
                    return 0m;
                case DbType.Double:
                    return 0f;
                case DbType.Guid:
                    return Guid.Empty;
                case DbType.Int16:
                    return (short)0;
                case DbType.Int32:
                    return 0;
                case DbType.Int64:
                    return (long)0;
                case DbType.Object:
                    return null;
                case DbType.Single:
                    return 0F;
                case DbType.String:
                    return String.Empty;
                case DbType.StringFixedLength:
                    return string.Empty;
                case DbType.Time:
                    return DateTime.MinValue;
                case DbType.VarNumeric:
                    return 0;
                default:
                    return null;

            }
        }

        /// <summary>
        /// Convert out parameter.
        /// </summary>
        /// <param name="type">Type.</param>
        /// <param name="outputValue">outputValue.</param>
        /// <returns>Return Value.</returns>
        public static object ConvertOutParameter(DbType type, object outputValue)
        {
            object returnValue = null;

            if (Object.Equals(outputValue, GetDefaultValue(type)))
            {
                returnValue = DBNull.Value;
            }
            else
            {
                returnValue = outputValue;
            }

            return returnValue;
        }

        #endregion
    }
}
